/**************************************************************************** 
* 
* Copyright (c) 2023  C*Core -   All Rights Reserved  
* 
* THIS SOFTWARE IS DISTRIBUTED "AS IS," AND ALL WARRANTIES ARE DISCLAIMED, 
* INCLUDING MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* 
* PROJECT     : CCFC2011BC           
* DESCRIPTION : can demo code
* HISTORY     : Initial version.
* @file     can_demo.c
* @version  1.1
* @date     2023 - 02 - 20
* @brief    Initial version.
*
*****************************************************************************/

#include "can_demo.h"

static uint8_t g_fifo_recv_msg_ok = FALSE; /* PRQA S 1504 */
static uint8_t g_fifo_recv_msg2_ok = FALSE; /* PRQA S 1504, 1514 */
static uint8_t g_fifo_recv_msg4_ok = FALSE; /* PRQA S 1504 */
static uint8_t g_mb_send_msg_ok = FALSE; /* PRQA S 1504 */

/*******************************************************************************
 * @brief      CAN_Test_Case_1_1: CAN internal self-loopback test
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CAN_Test_Case_1_1(void)
{
    uint32_t ret;
    CANDriver *cand;
    CANConfig config;
    CANTxMsg tx_msg;
    CANRxMsg rx_msg;
    uint32_t msg_id;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.bit_rate = CAN_KBPS_500;
    config.func_switch.fifo_en = TRUE;
    config.func_switch.loop_back_en = TRUE;
    config.fifo[0].is_remote = FALSE;
    config.fifo[0].is_extern = TRUE;
    config.fifo[0].id = 0x11;
    config.fifo[0].mask = 0xffffffffU;
    config.can_id = CAN_MOD_ID_0;
    /* STEP2 Example Initialize the CAN module */
    ret = Can_LLD_Init(&cand, &config);
    if (ret != CAN_OK)
    {
        return ret;
    }
    /* STEP3 send message  */
    tx_msg.is_remote = FALSE;
    tx_msg.is_extern = TRUE;
    tx_msg.data_len = 8;
    tx_msg.id = 0x11;
    tx_msg.data.word[0] = 0x5a5a5a5aU;
    tx_msg.data.word[1] = 0xa5a5a5a5U;
    ret = Can_LLD_Send_Msg(cand, &tx_msg, &msg_id);
    if (ret != CAN_OK)
    {
        return ret;
    }
    while (Can_LLD_Is_Msg_Transferred(cand, msg_id) == FALSE)
    {
        ;
    }
    /* STEP4 Receive message */
    ret = Can_LLD_Recv_Msg_From_FIFO(cand, &rx_msg);
    if (ret != CAN_OK)
    {
        return ret;
    }
    if (rx_msg.data.word[0] != 0x5a5a5a5aU)
    {
        return CAN_ERROR_INVALID_MESSAGE;
    }

    return CAN_OK;
}

/*******************************************************************************
 * @brief      CAN_Test_Case_1_2: Self-loopback test with CAN transceiver (via MB) 
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CAN_Test_Case_1_2(void)
{
    uint32_t ret;
    CANDriver *cand;
    CANConfig config;
    CANTxMsg tx_msg;
    CANRxMsg rx_msg;
    uint32_t msg_id;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.bit_rate = CAN_KBPS_500;
    config.func_switch.fifo_en = TRUE;
    config.func_switch.loop_back_en = FALSE;
    config.buf_cfg.rx_mb_num = 4;
    config.mb[0].is_remote = FALSE;
    config.mb[0].is_extern = TRUE;
    config.mb[0].id = 0x12;
    config.mb[0].mask = 0xffffffffU;
    config.can_id = CAN_MOD_ID_0;
    /* STEP2 Example Initialize the CAN module */
    ret = Can_LLD_Init(&cand, &config);
    if (ret != CAN_OK)
    {
        return ret;
    }
    /* STEP3 send message  */
    tx_msg.is_remote = FALSE;
    tx_msg.is_extern = TRUE;
    tx_msg.data_len = 6;
    tx_msg.id = 0x12;
    tx_msg.data.word[0] = 0x5a5a5a5aU;
    tx_msg.data.word[1] = 0x87654321U;
    ret = Can_LLD_Send_Msg(cand, &tx_msg, &msg_id);
    if (ret != CAN_OK)
    {
        return ret;
    }
    while (Can_LLD_Is_Msg_Transferred(cand, msg_id) == FALSE)
    {
        ;
    }
    /* STEP4 Receive message */
    ret = Can_LLD_Recv_Msg_From_MB(cand, 0, &rx_msg);
    if (ret != CAN_OK)
    {
        return ret;
    }
    if (rx_msg.data.word[0] != 0x5a5a5a5aU)
    {
        return CAN_ERROR_INVALID_MESSAGE;
    }

    return CAN_OK;
}

/*******************************************************************************
 * @brief      CAN_Test_Case_1_4: Self-loopback test with CAN transceiver (via FIFO) 
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CAN_Test_Case_1_4(void)
{
    uint32_t ret;
    CANDriver *cand;
    CANConfig config;
    CANTxMsg tx_msg;
    CANRxMsg rx_msg;
    uint32_t msg_id;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.bit_rate = CAN_KBPS_500;
    config.func_switch.fifo_en = TRUE;
    config.func_switch.loop_back_en = FALSE;
    config.fifo[0].is_remote = FALSE;
    config.fifo[0].is_extern = TRUE;
    config.fifo[0].id = 0x14;
    config.fifo[0].mask = 0xffffffffU;
    config.can_id = CAN_MOD_ID_0;
    /* STEP2 Example Initialize the CAN module */
    ret = Can_LLD_Init(&cand, &config);
    if (ret != CAN_OK)
    {
        return ret;
    }
    /* STEP3 send message  */
    tx_msg.is_remote = FALSE;
    tx_msg.is_extern = TRUE;
    tx_msg.data_len = 8;
    tx_msg.id = 0x14;
    tx_msg.data.word[0] = 0x5a5a5a5aU;
    tx_msg.data.word[1] = 0xffffffffU;
    ret = Can_LLD_Send_Msg(cand, &tx_msg, &msg_id);
    if (ret != CAN_OK)
    {
        return ret;
    }
    while (Can_LLD_Is_Msg_Transferred(cand, msg_id) == FALSE)
    {
        ;
    }
    /* STEP4 Receive message */
    ret = Can_LLD_Recv_Msg_From_FIFO(cand, &rx_msg);
    if (ret != CAN_OK)
    {
        return ret;
    }
    if (rx_msg.data.word[0] != 0x5a5a5a5aU)
    {
        return CAN_ERROR_INVALID_MESSAGE;
    }

    return CAN_OK;
}

/*******************************************************************************
 * @brief      CAN_Test_Case_2_1: The CAN module sends messages to the PC
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CAN_Test_Case_2_1(void)
{
    uint32_t ret;
    CANDriver *cand;
    CANConfig config;
    CANTxMsg tx_msg;
    CANRxMsg rx_msg;
    uint32_t msg_id;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.bit_rate = CAN_KBPS_500;
    config.func_switch.fifo_en = TRUE;
    config.func_switch.loop_back_en = FALSE;
    config.fifo[0].is_remote = FALSE;
    config.fifo[0].is_extern = TRUE;
    config.fifo[0].id = 0x21;
    config.fifo[0].mask = 0xffffffffU;
    config.can_id = CAN_MOD_ID_0;
    /* STEP2 Example Initialize the CAN module */
    ret = Can_LLD_Init(&cand, &config);
    if (ret != CAN_OK)
    {
        return ret;
    }
    /* STEP3 send message  */
    tx_msg.is_remote = FALSE;
    tx_msg.is_extern = TRUE;
    tx_msg.data_len = 8;
    tx_msg.id = 0x21;
    tx_msg.data.word[0] = 0x5a5a5a5aU;
    tx_msg.data.word[1] = 0xa5a5a5a5U;
    ret = Can_LLD_Send_Msg(cand, &tx_msg, &msg_id);
    if (ret != CAN_OK)
    {
        return ret;
    }
    while (Can_LLD_Is_Msg_Transferred(cand, msg_id) == FALSE)
    {
        ;
    }
    /* STEP4 View messages on PC */

    return CAN_OK;
}

/*******************************************************************************
 * @brief      CAN_Test_Case_2_2: PC sends message to CAN module (via FIFO)
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CAN_Test_Case_2_2(void)
{
    uint32_t ret;
    CANDriver *cand;
    CANConfig config;
    CANRxMsg rx_msg;
    uint32_t timeout = 20;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.bit_rate = CAN_KBPS_500;
    config.func_switch.fifo_en = TRUE;
    config.func_switch.loop_back_en = FALSE;
    config.func_switch.bcc_en = TRUE;
    config.fifo[0].is_remote = FALSE;
    config.fifo[0].is_extern = TRUE;
    config.fifo[0].id = 0x6c0;
    config.fifo[0].mask = 0xfffffff0U;
    config.can_id = CAN_MOD_ID_0;
    /* STEP2 Example Initialize the CAN module */
    ret = Can_LLD_Init(&cand, &config);
    if (ret != CAN_OK)
    {
        return ret;
    }
    /* STEP3 PC send message  */
    /* STEP4 Receive message */
    while (timeout-- != 0) /* PRQA S 1843, 3440 */
    {
        ret = Can_LLD_Recv_Msg_From_FIFO(cand, &rx_msg);
        if (ret == CAN_OK)
        {
            break;
        }
        delayms(1);
    }
    if (rx_msg.data.word[0] != 0x5a5a5a5aU)
    {
        return CAN_ERROR_INVALID_MESSAGE;
    }

    return CAN_OK;
}

/*******************************************************************************
 * @brief      CAN_Test_Case_2_3: PC sends message to CAN module (via MB)
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CAN_Test_Case_2_3(void)
{
    uint32_t ret;
    CANDriver *cand;
    CANConfig config;
    CANRxMsg rx_msg;
    uint32_t timeout = 20;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.bit_rate = CAN_KBPS_500;
    config.func_switch.fifo_en = FALSE;
    config.func_switch.loop_back_en = FALSE;
    config.func_switch.bcc_en = TRUE;
    config.buf_cfg.rx_mb_num = 1;
    config.mb[0].is_remote = FALSE;
    config.mb[0].is_extern = FALSE;
    config.mb[0].id = 0x6c0;
    config.mb[0].mask = 0xffff0;
    config.can_id = CAN_MOD_ID_0;
    /* STEP2 Example Initialize the CAN module */
    ret = Can_LLD_Init(&cand, &config);
    if (ret != CAN_OK)
    {
        return ret;
    }
    /* STEP3 PC send message  */
    /* STEP4 Receive message */
    while (timeout-- != 0) /* PRQA S 1843, 3440 */
    {
        ret = Can_LLD_Recv_Msg_From_MB(cand, 0, &rx_msg);
        if (ret == CAN_OK)
        {
            break;
        }
        delayms(1);
    }
    if (rx_msg.data.word[0] != 0x5a5a5a5aU)
    {
        return CAN_ERROR_INVALID_MESSAGE;
    }

    return CAN_OK;
}

/*******************************************************************************
 * @brief      CAN_Test_Case_3_1: six The CAN module sends messages to the PC
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CAN_Test_Case_3_1(void)
{
    uint32_t ret;
    uint32_t can_id;
    CANDriver *cand[CAN_MOD_BUTT];
    CANConfig config;
    CANTxMsg tx_msg;
    CANRxMsg rx_msg;
    uint32_t msg_id;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.bit_rate = CAN_KBPS_500;
    config.func_switch.fifo_en = TRUE;
    config.func_switch.loop_back_en = FALSE;
    config.fifo[0].is_remote = FALSE;
    config.fifo[0].is_extern = TRUE;
    config.fifo[0].id = 0x31;
    config.fifo[0].mask = 0xffffffffU;
    /* STEP2 Example Initialize the CAN module */
    for (can_id = 0; can_id < (uint32_t)CAN_MOD_BUTT; can_id++)
    {
        config.can_id = (CANModId)can_id; /* PRQA S 4342 */
        ret = Can_LLD_Init(&cand[can_id], &config);
        if (ret != CAN_OK)
        {
            return ret;
        }
    }
    /* STEP3 send message  */
    tx_msg.is_remote = FALSE;
    tx_msg.is_extern = TRUE;
    tx_msg.data_len = 8;
    tx_msg.data.word[0] = 0x5a5a5a5a;
    for (can_id = 0; can_id < (uint32_t)CAN_MOD_BUTT; can_id++)
    {
        /* STEP3 send message  */
        /* Messages sent by different CAN modules carry can_id for verification after receiving */
        tx_msg.data.word[1] = can_id;
        tx_msg.id = can_id;
        ret = Can_LLD_Send_Msg(cand[can_id], &tx_msg, &msg_id);
        if (ret != CAN_OK)
        {
            return ret;
        }
        delayms(200);
    }
    /* STEP4 View messages on PC */

    return CAN_OK;
}


/*******************************************************************************
 * @brief      CAN_Test_Case_3_2: The PC sends messages to the six CAN module
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CAN_Test_Case_3_2(void)
{
    uint32_t ret;
    uint32_t can_id;
    CANDriver *cand[CAN_MOD_BUTT];
    CANConfig config;
    CANRxMsg rx_msg[CAN_MOD_BUTT];
    uint32_t timeout;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.bit_rate = CAN_KBPS_500;
    config.func_switch.fifo_en = TRUE;
    config.func_switch.loop_back_en = FALSE;
    config.fifo[0].is_remote = FALSE;
    config.fifo[0].is_extern = TRUE;
    config.fifo[0].mask = 0xffffffffU;
    /* STEP2 Example Initialize the CAN module */
    for (can_id = 0; can_id < (uint32_t)CAN_MOD_BUTT; can_id++)
    {
        config.can_id = (CANModId)can_id; /* PRQA S 1504, 4342 */
        config.fifo[0].id = can_id;
        ret = Can_LLD_Init(&cand[can_id], &config);
        if (ret != CAN_OK)
        {
            return ret;
        }
    }
    /* STEP3 PC send message  */
    /* STEP4 Receive message */
    for (can_id = 0; can_id < (uint32_t)CAN_MOD_BUTT; can_id++)
    {
        timeout = 20;
        while (timeout-- != 0) /* PRQA S 1843, 3440 */
        {
            ret = Can_LLD_Recv_Msg_From_FIFO(cand[can_id], &rx_msg[can_id]);
            if (ret == CAN_OK)
            {
               break;
            }
            delayms(1);
        }
        if (rx_msg[can_id].data.word[1] != can_id)
        {
            return CAN_ERROR_INVALID_MESSAGE;
        }
    }

    return CAN_OK;
}

/*******************************************************************************
 * @brief      CAN_Test_Case_4_1_Interrupt_Callback
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void CAN_Test_Case_4_1_Interrupt_Callback(void) /* PRQA S 3219 */
{
    uint32_t ret;
    CANTxMsg tx_msg;
    CANDriver cand;
    uint32_t msg_id;

    cand.id = CAN_MOD_ID_1;

    tx_msg.is_remote = FALSE;
    tx_msg.is_extern = TRUE;
    tx_msg.data_len = 8;
    tx_msg.id = 0x41;
    tx_msg.data.word[0] = 0x5a5a5a5a;
    tx_msg.data.word[1] = 0x11111111;
    ret = Can_LLD_Send_Msg(&cand, &tx_msg, &msg_id);
    if (ret != CAN_OK)
    {
        return ;
    }
}

/*******************************************************************************
 * @brief      CAN_Test_Case_4_1 Foreground programs and periodic interrupts 
 *                                 use different CAN modules to send messages
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CAN_Test_Case_4_1(void)
{
    uint32_t ret;
    CANDriver *cand;
    CANConfig config;
    CANTxMsg tx_msg;
    CANRxMsg rx_msg;
    uint32_t msg_id;
    uint32_t timeout = 20;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.bit_rate = CAN_KBPS_500;
    config.func_switch.fifo_en = TRUE;
    config.func_switch.loop_back_en = FALSE;
    config.fifo[0].is_remote = FALSE;
    config.fifo[0].is_extern = TRUE;
    config.fifo[0].id = 0x41;
    config.fifo[0].mask = 0xffffffffU;
    /* STEP2 Example Initialize the CAN module */
    config.can_id = CAN_MOD_ID_1;
    ret = Can_LLD_Init(&cand, &config);
    if (ret != CAN_OK)
    {
        return ret;
    }
    config.can_id = CAN_MOD_ID_0;
    ret = Can_LLD_Init(&cand, &config);
    if (ret != CAN_OK)
    {
        return ret;
    }
    /* STEP3 Mount interrupt, send message in interrupt  */
    while (timeout-- != 0) /* PRQA S 1843, 3440 */
    {
        /* STEP4 front desksend message  */
        tx_msg.is_remote = FALSE;
        tx_msg.is_extern = TRUE;
        tx_msg.data_len = 8;
        tx_msg.id = 0x41;
        tx_msg.data.word[0] = 0x5a5a5a5a;
        tx_msg.data.word[1] = 0x0;
        ret = Can_LLD_Send_Msg(cand, &tx_msg, &msg_id);
        if (ret != CAN_OK)
        {
            return ret;
        }
        while (Can_LLD_Is_Msg_Transferred(cand, msg_id) == FALSE)
        {
            ;
        }
        delayms(1);
        /* STEP5 View messages on PC */
    }

    return CAN_OK;
}

/*******************************************************************************
 * @brief      Fifo_Recv_Msg_Callback
 * @param[in]  CANDriver *drv, CANRxMsg * rx_msg
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void Fifo_Recv_Msg_Callback(CANDriver *drv, CANRxMsg * rx_msg) /* PRQA S 3673 */
{
    if (drv->id != CAN_MOD_ID_0)
    {
        return ;
    }
    if (rx_msg->data.word[0] != 0x5a5a5a5aU)
    {
        return ;
    }
    g_fifo_recv_msg_ok = TRUE;
}

/*******************************************************************************
 * @brief      Mb_Recv_Msg_Callback
 * @param[in]  CANDriver *drv, uint32_t mb_idx, CANRxMsg *rx_msg
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void Mb_Recv_Msg_Callback(CANDriver *drv, uint32_t mb_idx, CANRxMsg *rx_msg) /* PRQA S 3673 */
{
    if (drv->id != CAN_MOD_ID_0)
    {
        return ;
    }
    if (rx_msg->data.word[0] != 0x5a5a5a5aU)
    {
        return ;
    }
    if (mb_idx != 8U)
    {
        return ;
    }
}

/*******************************************************************************
 * @brief      Mb_Send_Msg_Callback
 * @param[in]  CANDriver *drv, uint32_t mb_idx
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void Mb_Send_Msg_Callback(CANDriver *drv, uint32_t mb_idx) /* PRQA S 3206, 3673 */
{
    if (drv->id != CAN_MOD_ID_0)
    {
        return ;
    }
    mb_idx = mb_idx; /* PRQA S 1338, 2983 */
    g_mb_send_msg_ok = TRUE;
}

/*******************************************************************************
 * @brief      CAN_Test_Case_5_1Receive a message in an interrupt callback 
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CAN_Test_Case_5_1(void)
{
    uint32_t ret;
    CANDriver *cand;
    CANConfig config;
    CANTxMsg tx_msg;
    CANRxMsg rx_msg;
    uint32_t msg_id;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.bit_rate = CAN_KBPS_500;
    config.func_switch.fifo_en = TRUE;
    config.func_switch.loop_back_en = FALSE;
    config.fifo[0].is_remote = FALSE;
    config.fifo[0].is_extern = FALSE;
    config.fifo[0].id = 1;
    config.fifo[0].mask = 0xffffffffU;
    config.call_back.rx_fifo_msg_received = Fifo_Recv_Msg_Callback;
    config.can_id = CAN_MOD_ID_0;
    /* STEP2 Example Initialize the CAN module */
    ret = Can_LLD_Init(&cand, &config);
    if (ret != CAN_OK)
    {
        return ret;
    }
    /* STEP3 send message  */
    tx_msg.is_remote = FALSE;
    tx_msg.is_extern = FALSE;
    tx_msg.data_len = 8;
    tx_msg.id = 1;
    tx_msg.data.word[0] = 0x5a5a5a5aU;
    tx_msg.data.word[1] = 0xffffffffU;
    ret = Can_LLD_Send_Msg(cand, &tx_msg, &msg_id);
    if (ret != CAN_OK)
    {
        return ret;
    }
    while (Can_LLD_Is_Msg_Transferred(cand, msg_id) == FALSE)
    {
        ;
    }
    /* STEP4 Receive message */
    delayms(20);
    if (g_fifo_recv_msg_ok == FALSE)
    {
        return ~CAN_OK;
    }

    return CAN_OK;
}

/*******************************************************************************
 * @brief      CAN_Test_Case_5_2 An interrupt notification was received after 
 *                                the message was sent asynchronously. Procedure
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CAN_Test_Case_5_2(void)
{
    uint32_t ret;
    CANDriver *cand;
    CANConfig config;
    CANTxMsg tx_msg;
    CANRxMsg rx_msg;
    uint32_t msg_id;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.bit_rate = CAN_KBPS_500;
    config.func_switch.fifo_en = TRUE;
    config.func_switch.loop_back_en = FALSE;
    config.buf_cfg.rx_mb_num = 4;
    config.mb[0].is_remote = FALSE;
    config.mb[0].is_extern = TRUE;
    config.mb[0].id = 0x52;
    config.mb[0].mask = 0xffffffffU;
    config.call_back.tx_mb_msg_transferred = Mb_Send_Msg_Callback;
    config.call_back.rx_mb_msg_received = Mb_Recv_Msg_Callback;
    config.can_id = CAN_MOD_ID_0;
    /* STEP2 Example Initialize the CAN module */
    ret = Can_LLD_Init(&cand, &config);
    if (ret != CAN_OK)
    {
        return ret;
    }
    /* STEP3 send message  */
    tx_msg.is_remote = FALSE;
    tx_msg.is_extern = TRUE;
    tx_msg.data_len = 8;
    tx_msg.id = 0x52;
    tx_msg.data.word[0] = 0x5a5a5a5aU;
    tx_msg.data.word[1] = 0xffffffffU;
    ret = Can_LLD_Send_Msg(cand, &tx_msg, &msg_id);
    if (ret != CAN_OK)
    {
        return ret;
    }
    while (Can_LLD_Is_Msg_Transferred(cand, msg_id) == FALSE)
    {
        ;
    }

    delayms(20);
    if (g_mb_send_msg_ok == FALSE)
    {
        return ~CAN_OK;
    }

    return CAN_OK;
}

/*******************************************************************************
 * @brief      CAN_Test_Case_6_1 Sleep and wake up after initialization
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CAN_Test_Case_6_1(void)
{
    uint32_t ret;
    CANDriver *cand;
    CANConfig config;
    CANTxMsg tx_msg;
    CANRxMsg rx_msg;
    uint32_t msg_id;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.bit_rate = CAN_KBPS_500;
    config.func_switch.fifo_en = TRUE;
    config.func_switch.loop_back_en = FALSE;
    config.buf_cfg.rx_mb_num = 4;
    config.mb[0].is_remote = FALSE;
    config.mb[0].is_extern = TRUE;
    config.mb[0].id = 0x61;
    config.mb[0].mask = 0xffffffffU;
    config.can_id = CAN_MOD_ID_0;
    /* STEP2 Example Initialize the CAN module */
    ret = Can_LLD_Init(&cand, &config);
    if (ret != CAN_OK)
    {
        return ret;
    }
    /* STEP3 sleep */
    Can_LLD_Sleep(cand);
    /* STEP4 wakeup */
    Can_LLD_Wakeup(cand);
    /* STEP3 send message  */
    tx_msg.is_remote = FALSE;
    tx_msg.is_extern = TRUE;
    tx_msg.data_len = 8;
    tx_msg.id = 0x61;
    tx_msg.data.word[0] = 0x5a5a5a5aU;
    tx_msg.data.word[1] = 0xffffffffU;
    ret = Can_LLD_Send_Msg(cand, &tx_msg, &msg_id);
    if (ret != CAN_OK)
    {
        return ret;
    }
    while (Can_LLD_Is_Msg_Transferred(cand, msg_id) == FALSE)
    {
        ;
    }
    /* STEP4 Receive message */
    ret = Can_LLD_Recv_Msg_From_MB(cand, 0, &rx_msg);
    if (ret != CAN_OK)
    {
        return ret;
    }
    if (rx_msg.data.word[0] != 0x5a5a5a5aU)
    {
        return CAN_ERROR_INVALID_MESSAGE;
    }

    return CAN_OK;
}

/*******************************************************************************
 * @brief      CAN_Test_Case_6_2 Sleep and wake up between tasks
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CAN_Test_Case_6_2(void)
{
    uint32_t ret;
    CANDriver *cand;
    CANConfig config;
    CANTxMsg tx_msg;
    CANRxMsg rx_msg;
    uint32_t msg_id;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.bit_rate = CAN_KBPS_500;
    config.func_switch.fifo_en = TRUE;
    config.func_switch.loop_back_en = FALSE;
    config.buf_cfg.rx_mb_num = 4;
    config.mb[0].is_remote = FALSE;
    config.mb[0].is_extern = TRUE;
    config.mb[0].id = 0x62;
    config.mb[0].mask = 0xffffffffU;
    config.can_id = CAN_MOD_ID_0;
    /* STEP2 Example Initialize the CAN module */
    ret = Can_LLD_Init(&cand, &config);
    if (ret != CAN_OK)
    {
        return ret;
    }
    /* STEP3 send message  */
    tx_msg.is_remote = FALSE;
    tx_msg.is_extern = TRUE;
    tx_msg.data_len = 8;
    tx_msg.id = 0x62;
    tx_msg.data.word[0] = 0x5a5a5a5a;
    ret = Can_LLD_Send_Msg(cand, &tx_msg, &msg_id);
    if (ret != CAN_OK)
    {
        return ret;
    }
    while (Can_LLD_Is_Msg_Transferred(cand, msg_id) == FALSE)
    {
        ;
    }
    /* STEP3 sleep */
    Can_LLD_Sleep(cand);
    /* STEP4 wakeup */
    Can_LLD_Wakeup(cand);
    /* STEP4 Receive message */
    ret = Can_LLD_Recv_Msg_From_MB(cand, 0, &rx_msg);
    if (ret != CAN_OK)
    {
        return ret;
    }
    if (rx_msg.data.word[0] != 0x5a5a5a5aU)
    {
        return CAN_ERROR_INVALID_MESSAGE;
    }

    return CAN_OK;
}

/*******************************************************************************
 * @brief      Fifo_Recv_Msg_Callback2
 * @param[in]  CANDriver *drv, CANRxMsg * rx_msg
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void Fifo_Recv_Msg_Callback2(CANDriver *drv, CANRxMsg * rx_msg) /* PRQA S 3206, 3673 */
{
    union CanFrame canFrame;

    canFrame.byte[3] = rx_msg->data.byte[0];
    canFrame.byte[2] = rx_msg->data.byte[1];
    canFrame.byte[1] = rx_msg->data.byte[2];
    canFrame.byte[0] = rx_msg->data.byte[3];
    canFrame.byte[4+3] = rx_msg->data.byte[4+0];
    canFrame.byte[4+2] = rx_msg->data.byte[4+1];
    canFrame.byte[4+1] = rx_msg->data.byte[4+2];
    canFrame.byte[4+0] = rx_msg->data.byte[4+3];
    drv = drv; /* PRQA S 1338, 2983 */
    g_fifo_recv_msg2_ok = TRUE;
}

/*******************************************************************************
 * @brief      CAN_Test_Case_7_1 Sends messages to other nodes in small-endian
 *                                format
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CAN_Test_Case_7_1(void)
{
    uint32_t ret;
    CANDriver *cand;
    CANConfig config;
    CANTxMsg tx_msg;
    CANRxMsg rx_msg;
    uint32_t msg_id;
    union CanFrame canFrame;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));
    cc_memset((uint8_t *)&canFrame, 0, sizeof(canFrame));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.bit_rate = CAN_KBPS_500;
    config.func_switch.fifo_en = TRUE;
    config.func_switch.loop_back_en = FALSE;
    config.fifo[0].is_remote = FALSE;
    config.fifo[0].is_extern = FALSE;
    config.fifo[0].id = 1;
    config.fifo[0].mask = 0xffffffffU;
    config.can_id = CAN_MOD_ID_0;
    /* STEP2 Example Initialize the CAN module */
    ret = Can_LLD_Init(&cand, &config);
    if (ret != CAN_OK)
    {
        return ret;
    }
    /* STEP3 send message  */
    canFrame.u64.CFG_TX_SID = 2; // 11;
    canFrame.u64.CFG_TX_EID = 4; // 18;
    canFrame.u64.CFG_TX_IDE = 1; // 1;
    canFrame.u64.CFG_REQ = 2; // 2;
    canFrame.u64.CFG_IDX = 8; // 6;
    canFrame.u64.CFG_REQ_TEC_REC = 1; // 2;
    canFrame.u64.CFG_TX_DLC = 2; // 4;
    canFrame.u64.CFG_TX_ESI_r0 = 1; // 1;
    canFrame.u64.CFG_TX_BRS = 1; // 1;
    canFrame.u64.CFG_TX_RTR_RRS = 1; // 1;
    canFrame.u64.CFG_TX_FDF = 1; // 1;
    canFrame.u64.CFG_TX_Data0 = 128; // 8;
    canFrame.u64.CFG_TX_Other_Data = 254; // 8;

    tx_msg.is_remote = FALSE;
    tx_msg.is_extern = FALSE;
    tx_msg.data_len = 8;
    tx_msg.id = 1;
    tx_msg.data.byte[0] = canFrame.byte[3];
    tx_msg.data.byte[1] = canFrame.byte[2];
    tx_msg.data.byte[2] = canFrame.byte[1];
    tx_msg.data.byte[3] = canFrame.byte[0];
    tx_msg.data.byte[4+0] = canFrame.byte[4+3];
    tx_msg.data.byte[4+1] = canFrame.byte[4+2];
    tx_msg.data.byte[4+2] = canFrame.byte[4+1];
    tx_msg.data.byte[4+3] = canFrame.byte[4+0];
    ret = Can_LLD_Send_Msg(cand, &tx_msg, &msg_id);
    if (ret != CAN_OK)
    {
        return ret;
    }
    while (Can_LLD_Is_Msg_Transferred(cand, msg_id) == FALSE)
    {
        ;
    }
    /* STEP4 compare message */

    return CAN_OK;
}

/*******************************************************************************
 * @brief      CAN_Test_Case_7_2 Receive messages from other nodes in 
 *                                small-endian format
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CAN_Test_Case_7_2(void)
{
    uint32_t ret;
    CANDriver *cand;
    CANConfig config;
    CANTxMsg tx_msg;
    CANRxMsg rx_msg;
    union CanFrame canFrame;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));
    cc_memset((uint8_t *)&canFrame, 0, sizeof(canFrame));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.bit_rate = CAN_KBPS_500;
    config.func_switch.fifo_en = TRUE;
    config.func_switch.loop_back_en = FALSE;
    config.fifo[0].is_remote = FALSE;
    config.fifo[0].is_extern = FALSE;
    config.fifo[0].id = 1;
    config.fifo[0].mask = 0xffffffffU;
    config.call_back.rx_fifo_msg_received = Fifo_Recv_Msg_Callback2;
    config.can_id = CAN_MOD_ID_0;
    /* STEP2 Example Initialize the CAN module */
    ret = Can_LLD_Init(&cand, &config);
    if (ret != CAN_OK)
    {
        return ret;
    }
    /* STEP3 Sending a message on the PC */
    /* STEP4 Receive message */
    delayms(20);
    if (g_fifo_recv_msg2_ok == FALSE)
    {
        return ~CAN_OK;
    }
    return CAN_OK;
}

/*******************************************************************************
 * @brief      Fifo_Recv_Msg_Callback4
 * @param[in]  CANDriver *drv, CANRxMsg * rx_msg
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void Fifo_Recv_Msg_Callback4(CANDriver *drv, CANRxMsg * rx_msg) /* PRQA S 3206, 3673 */
{
    volatile union CanFrameREQ_DATA canFrameREQ_DATA;

    canFrameREQ_DATA.byte = rx_msg->data.byte[0];
    drv = drv; /* PRQA S 1338, 2983 */
    rx_msg = rx_msg; /* PRQA S 1338, 2983 */
    g_fifo_recv_msg4_ok = TRUE;
}

/*******************************************************************************
 * @brief      CAN_Test_Case_8_1 Send a single BYTE message in small-endian format 
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CAN_Test_Case_8_1(void)
{
    uint32_t ret;
    CANDriver *cand;
    CANConfig config;
    CANTxMsg tx_msg;
    CANRxMsg rx_msg;
    uint32_t msg_id;
    union CanFrameREQ_DATA canFrameREQ_DATA;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.bit_rate = CAN_KBPS_500;
    config.func_switch.fifo_en = TRUE;
    config.func_switch.loop_back_en = FALSE;
    config.fifo[0].is_remote = FALSE;
    config.fifo[0].is_extern = FALSE;
    config.fifo[0].id = 2;
    config.fifo[0].mask = 0xffffffffU;
    config.can_id = CAN_MOD_ID_0;
    /* STEP2 Example Initialize the CAN module */
    ret = Can_LLD_Init(&cand, &config);
    if (ret != CAN_OK)
    {
        return ret;
    }
    /* STEP3 send message  */
    canFrameREQ_DATA.B.REQ_DATA_BACK = 1;
    canFrameREQ_DATA.B.REQ_TEC_REC = 2;

    tx_msg.is_remote = FALSE;
    tx_msg.is_extern = FALSE;
    tx_msg.data_len = 1;
    tx_msg.id = 2;
    tx_msg.data.byte[0] = (uint8_t)canFrameREQ_DATA.byte;
    ret = Can_LLD_Send_Msg(cand, &tx_msg, &msg_id);
    if (ret != CAN_OK)
    {
        return ret;
    }
    while (Can_LLD_Is_Msg_Transferred(cand, msg_id) == FALSE)
    {
        ;
    }
    /* STEP4 Receive message */
    delayms(20);
    if (g_fifo_recv_msg_ok == FALSE)
    {
        return ~CAN_OK;
    }

    return CAN_OK;
}

/*******************************************************************************
 * @brief      CAN_Test_Case_8_2 Receives a single BYTE message in  
 *                                small-endian format 
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CAN_Test_Case_8_2(void)
{
    uint32_t ret;
    CANDriver *cand;
    CANConfig config;
    CANTxMsg tx_msg;
    CANRxMsg rx_msg;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.bit_rate = CAN_KBPS_500;
    config.func_switch.fifo_en = TRUE;
    config.func_switch.loop_back_en = FALSE;
    config.fifo[0].is_remote = FALSE;
    config.fifo[0].is_extern = FALSE;
    config.fifo[0].id = 2;
    config.fifo[0].mask = 0xffffffffU;
    config.call_back.rx_fifo_msg_received = Fifo_Recv_Msg_Callback4;
    config.can_id = CAN_MOD_ID_0;
    /* STEP2 Example Initialize the CAN module */
    ret = Can_LLD_Init(&cand, &config);
    if (ret != CAN_OK)
    {
        return ret;
    }
    /* STEP3 Sending a message on the PC */
    /* STEP4 Receive message */
    delayms(20);
    if (g_fifo_recv_msg4_ok == FALSE)
    {
        return ~CAN_OK;
    }
    return CAN_OK;
}

/*******************************************************************************
 * @brief      CAN_TEST_Demo
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
uint32_t CAN_TEST_Demo(void)
{
    uint32_t ret;
    uint32_t idx;
    uint32_t can_id;
    const struct  {
        uint32_t (*func)(void);
        uint8_t auto_check;
    } can_ut[] = {
        /* Function: 00 Internal loopback test of CAN module */
        {CAN_Test_Case_1_1, TRUE},
        /* Function: 01 Self-loopback test with CAN transceiver (via MB) */
        {CAN_Test_Case_1_2, TRUE},
        /* Function: 02 Self-loopback test with CAN transceiver (via FIFO) */
        {CAN_Test_Case_1_4, TRUE},
        /* Function: 03 The CAN module sends messages to the PC */
        {CAN_Test_Case_2_1, TRUE},
        /* Function: 04 PC sends message to CAN module (via FIFO) */
        {CAN_Test_Case_2_2, FALSE /* A PC is required to send messages */},
        /* Function: 05 PC sends message to CAN module (via MB) */
        {CAN_Test_Case_2_3, FALSE /* A PC is required to send messages */},
        /* Function: 06 six The CAN module sends messages to the PC */
        {CAN_Test_Case_3_1, FALSE /* six connections are required */},
        /* Function: 07 The PC sends messages to the six CAN module */
        {CAN_Test_Case_3_2, FALSE /* six connections are required */},
        /* Function: 08 Foreground programs and periodic interrupts use different CAN modules to send messages */
        {CAN_Test_Case_4_1, TRUE},
        /* Function: 09 Receive a message in an interrupt callback */
        {CAN_Test_Case_5_1, TRUE},
        /* Function: 10 An interrupt notification was received after the message was sent asynchronously. Procedure */
        {CAN_Test_Case_5_2, TRUE},
        /* Function: 11 Sleep and wake up after initialization */
        {CAN_Test_Case_6_1, TRUE},
        /* Function: 12 Sleep and wake up between tasks */
        {CAN_Test_Case_6_2, TRUE},
        /* Function: 121 Sends messages to other nodes in small-endian format */
        {CAN_Test_Case_7_1, TRUE},
        /* Function: 14 Receive messages from other nodes in small-endian format */
        {CAN_Test_Case_7_2, FALSE /* A PC is required to send messages */},
        /* Function: 15 Send a single BYTE message in small-endian format */
        {CAN_Test_Case_8_1, TRUE},
        /* Function: 16 Receives a single BYTE message in small-endian format */
        {CAN_Test_Case_8_2, FALSE /* A PC is required to send messages */},
    };

    INTC.CPR.B.PRI = 0;

    for (idx = 0; idx < (sizeof(can_ut) / sizeof(can_ut[0])); idx++)
    {
        for (can_id = 0; can_id < (uint32_t)CAN_MOD_BUTT; can_id++)
        {
            (void)Can_LLD_DeInit(Can_LLD_Get_Driver((CANModId)can_id)); /* PRQA S 4342 */
        }
        ret = (can_ut[idx].func != NULL) ? can_ut[idx].func() : CAN_OK;
        if (ret == CAN_OK)
        {
            continue;
        }
        else if (can_ut[idx].auto_check == FALSE)
        {
            (void)PSPRINTF("\n CCFC2011BC CAN_TEST_Demo: call %x[%x] fail, ret = 0x%x\n",
                can_ut[idx], idx, ret);
        }
        else
        {
            (void)PSPRINTF("\n CCFC2011BC CAN_TEST_Demo: FAIL\n");
            return ~CAN_OK;
        }
    }

    (void)PSPRINTF("\n CCFC2011BC CAN_TEST_Demo: OK\n");

    return CAN_OK;
}

